package com.nidu.demo.exception;

import com.alibaba.cola.dto.Response;
import com.alibaba.cola.exception.BizException;
import com.nidu.demo.common.exception.ErrorCodeConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

/**
 * 全局异常处理器
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理所有异常，主要是处理未知异常
     */
    @ExceptionHandler(Exception.class)
    public Response handleException(Exception ex) {
        log.error("[handleException]", ex);
        return Response.buildFailure(ErrorCodeConstants.INTERNAL_SERVER_ERROR.getCode(),
            ErrorCodeConstants.INTERNAL_SERVER_ERROR.getMessage());
    }

    /**
     * 处理业务异常
     */
    @ExceptionHandler(value = BizException.class)
    public Response handleBizException(BizException ex) {
        log.info("[handleBizException] {}", ex.getMessage());
        return Response.buildFailure(ex.getErrCode(), ex.getMessage());
    }

    /**
     * 处理 SpringMVC 请求参数缺失
     */
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public Response handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
        log.warn("[handleMissingServletRequestParameterException]", ex);
        return Response.buildFailure(ErrorCodeConstants.BAD_REQUEST.getCode(),
            String.format("请求参数缺失:%s", ex.getParameterName()));
    }

    /**
     * 处理 SpringMVC 请求参数类型错误
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Response handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex) {
        log.warn("[handleMethodArgumentTypeMismatchException]", ex);
        return Response.buildFailure(ErrorCodeConstants.BAD_REQUEST.getCode(),
            String.format("请求参数类型错误:%s", ex.getMessage()));
    }

    /**
     * 处理 SpringMVC 参数校验不正确
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Response handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
        log.warn("[handleMethodArgumentNotValidException]", ex);
        FieldError fieldError = ex.getBindingResult().getFieldError();
        assert fieldError != null; // 断言，避免告警
        return Response.buildFailure(ErrorCodeConstants.BAD_REQUEST.getCode(),
            String.format("请求参数不正确:%s", fieldError.getDefaultMessage()));
    }

    /**
     * 处理 SpringMVC 参数绑定不正确，本质上也是通过 Validator 校验
     */
    @ExceptionHandler(BindException.class)
    public Response handleBindException(BindException ex) {
        log.warn("[handleBindException]", ex);
        FieldError fieldError = ex.getFieldError();
        assert fieldError != null; // 断言，避免告警
        return Response.buildFailure(ErrorCodeConstants.BAD_REQUEST.getCode(),
            String.format("请求参数不正确:%s", fieldError.getDefaultMessage()));
    }

    /**
     * 处理 Validator 校验不通过产生的异常
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    public Response handleConstraintViolationException(ConstraintViolationException ex) {
        log.warn("[handleConstraintViolationException]", ex);
        ConstraintViolation<?> constraintViolation = ex.getConstraintViolations().iterator().next();
        return Response.buildFailure(ErrorCodeConstants.BAD_REQUEST.getCode(),
            String.format("请求参数不正确:%s", constraintViolation.getMessage()));
    }

    /**
     * 处理 SpringMVC 请求方法不正确
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Response handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) {
        log.warn("[handleHttpRequestMethodNotSupportedException]", ex);
        return Response.buildFailure(ErrorCodeConstants.METHOD_NOT_ALLOWED.getCode(),
                "请求方法不正确");
    }


} 